// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;

namespace SnapObjects.Data
{
    internal abstract class SqlInsertStatementParser : SqlStatementParser
    {
        public SqlInsertStatementParser(
            ISqlStatementFactory factory, ISqlGenerationHelper helper) : base(factory, helper)
        {
        }

        public override SqlStatement ParseStatement(ISqlTokenizer tokenizer, bool isClause)
        {
            _isClause = isClause;

            var insert = new SqlInsertStatement();

            while (tokenizer.MoveNext())
            {
                if (tokenizer.Current is SqlKeywordToken token)
                {
                    if (token.Keyword == SqlKeywords.INSERT && tokenizer.MoveNext())
                    {
                        this.ParseInsertTable(tokenizer, insert);

                        this.ParseInsertColumns(tokenizer, insert);

                        this.ParseInsertValues(tokenizer, insert);

                        this.ParseInsertTerminator(tokenizer, insert);
                    }
                    else
                    {
                        throw new InvalidCastException(tokenizer.Current.Text);
                    }
                }
                else
                {
                    throw new InvalidCastException(tokenizer.Current.Text);
                }
            }

            return insert;
        }

        protected virtual bool ParseInsertTable(ISqlTokenizer tokenizer, SqlInsertStatement statement)
        {
            var result = false;

            if (tokenizer.MoveNext())
            {
                if (tokenizer.Current is SqlKeywordToken key && key.Keyword == SqlKeywords.INTO)
                {
                    while (tokenizer.MoveNext())
                    {
                        if ((tokenizer.Current is SqlCharacterToken character
                            && character.Character == SqlCharacters.OpenParentheses)
                            || (tokenizer.Current is SqlKeywordToken keyword
                            && keyword.Keyword == SqlKeywords.VALUES))
                        {
                            result = true;
                            break;
                        }

                        if (!String.IsNullOrWhiteSpace(tokenizer.Current.Text))
                        {
                            statement.Table.Add(tokenizer.Current);
                        }
                    }
                }
            }

            return result;
        }

        protected virtual bool ParseInsertColumns(ISqlTokenizer tokenizer, SqlInsertStatement statement)
        {
            var result = false;

            if (tokenizer.Current is SqlCharacterToken character
                && character.Character == SqlCharacters.OpenParentheses)
            {
                while (tokenizer.MoveNext())
                {
                    if (tokenizer.Current is SqlKeywordToken key
                        && key.Keyword == SqlKeywords.VALUES)
                    {
                        result = true;
                        break;
                    }
                    else if (tokenizer.Current is SqlCharacterToken c
                        && c.Character == SqlCharacters.CloseParentheses)
                    {
                        continue;
                    }

                    if (!String.IsNullOrWhiteSpace(tokenizer.Current.Text))
                    {
                        statement.Into.Add(tokenizer.Current);
                    }
                }
            }

            return result;
        }

        protected virtual bool ParseInsertValues(ISqlTokenizer tokenizer, SqlInsertStatement statement)
        {
            var result = false;

            if (tokenizer.Current is SqlKeywordToken keyword
                && keyword.Keyword == SqlKeywords.VALUES)
            {
                if (this.MoveToNotWhitespaceToken(tokenizer))
                {
                    if (tokenizer.Current is SqlCharacterToken character
                        && character.Character == SqlCharacters.OpenParentheses)
                    {
                        while (tokenizer.MoveNext())
                        {
                            if (tokenizer.Current is SqlCharacterToken ch
                                && ch.Character == SqlCharacters.CloseParentheses)
                            {
                                result = true;
                                break;
                            }

                            statement.Values.Add(tokenizer.Current);
                        }
                    }

                    //statement.Into.Add(tokenizer.Current);
                }
            }

            return result;
        }

        protected virtual bool ParseInsertTerminator(ISqlTokenizer tokenizer, SqlInsertStatement statement)
        {
            var result = false;

            if (tokenizer.Current is SqlCharacterToken character
                && character.Character == SqlCharacters.CloseParentheses)
            {
                while (tokenizer.MoveNext())
                {
                    statement.Terminator.Add(tokenizer.Current);
                }
            }

            return result;
        }

        private bool MoveToNotWhitespaceToken(ISqlTokenizer tokenizer)
        {
            tokenizer.MoveNext();

            if (tokenizer.Current is SqlToken token
                && token.Type == SqlTokenType.Whitespace)
            {
                while (tokenizer.MoveNext())
                {
                    if (tokenizer.Current is SqlCharacterToken sqlcharacter
                        && sqlcharacter.Character != SqlCharacters.Space)
                    {
                        return true;
                    }
                }

                return false;
            }

            return true;
        }
    }
}
